#include "tokensinput.h"
#include <QtGui/QGroupBox>
#include <QtGui/QVBoxLayout>
#include <QtGui/QHBoxLayout>
#include <QtCore/QStack>

TokensInput::TokensInput(GElement* const element, QWidget *parent)
	: mTokenModel(element, this), QSplitter(parent)
{
	setWindowFlags(Qt::Tool);
	setWindowTitle(element->elementName());
	setupUi();
	resize(480, 320);

	mTraceModel.setColumnCount(2);
	QStringList traceHeader;
	traceHeader << tr("Contains") << tr("Mount");
	mTraceModel.setHorizontalHeaderLabels(traceHeader);

	refresh();

	mTokenView->setModel(&mTokenModel);
	mTokenView->setSelectionMode(QAbstractItemView::SingleSelection);//QAbstractItemView::SingleSelection
	mTokenView->setItemDelegateForColumn(1,new TypeDelegate(this));
	mTraceView->setModel(&mTraceModel);

	//when user select a item with direction key, can't keep synchronization between three views. 
	//connect(mTokenView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(editToken(const QModelIndex &)));
	connect(mTokenView->selectionModel(), SIGNAL(currentChanged( const QModelIndex & , const QModelIndex & ) ),
		this, SLOT(editToken(const QModelIndex &)));
	connect(&mTokenModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
		this, SLOT(dataChanged(const QModelIndex &, const QModelIndex &)));
	connect(mValueWidget, SIGNAL(commit()), this, SLOT(commitValue()));

	connect(tokenUp, SIGNAL(clicked()), this, SLOT(moveUp()));
	connect(tokenDown, SIGNAL(clicked()), this, SLOT(moveDown()));
	connect(tokenAdd, SIGNAL(clicked()), this, SLOT(addToken()));
	connect(tokenDel, SIGNAL(clicked()), this, SLOT(deleteToken()));
	connect(traceAdd, SIGNAL(clicked()), this, SLOT(addTrace()));
	connect(traceDel, SIGNAL(clicked()), this, SLOT(deleteTrace()));
	connect(traceCommit, SIGNAL(clicked()), this, SLOT(commitTrace()));
}

TokensInput::~TokensInput()
{

}

void TokensInput::setupUi()
{
	QSplitter *splitter = this;
	splitter->setOrientation(Qt::Horizontal);

	QGroupBox *tokenBox = new QGroupBox(splitter);
	tokenBox->setTitle(tr("Tokens"));
	QVBoxLayout *vboxToken = new QVBoxLayout(tokenBox);
	mTokenView = new QTableView(tokenBox);
	vboxToken->addWidget(mTokenView);
	QHBoxLayout *hTokenButtons = new QHBoxLayout();
	hTokenButtons->addStretch(1);
	tokenUp = new QPushButton(tr("Up"), tokenBox);
	hTokenButtons->addWidget(tokenUp);
	tokenDown = new QPushButton(tr("Down"), tokenBox);
	hTokenButtons->addWidget(tokenDown);
	tokenAdd = new QPushButton(tr("Add"), tokenBox);
	hTokenButtons->addWidget(tokenAdd);
	tokenDel = new QPushButton(tr("Delete"), tokenBox);
	hTokenButtons->addWidget(tokenDel);
	vboxToken->addLayout(hTokenButtons);
	//splitter->addWidget(tokenBox);

	QSplitter *valueSplitter = new QSplitter(splitter);
	valueSplitter->setOrientation(Qt::Vertical);
	mValueWidget = new VariantInput(QVariant(), valueSplitter);
	//valueSplitter->addWidget(mValueWidget);

	QGroupBox *traceBox = new QGroupBox(valueSplitter);
	traceBox->setTitle(tr("Trace"));
	QVBoxLayout *vboxTrace = new QVBoxLayout(traceBox);
	mTraceView = new QTableView(traceBox);
	vboxTrace->addWidget(mTraceView);
	QHBoxLayout *traceButtons = new QHBoxLayout();
	traceButtons->addStretch(1);
	traceAdd = new QPushButton(tr("Add"), traceBox);
	traceButtons->addWidget(traceAdd);
	traceDel = new QPushButton(tr("Delete"), traceBox);
	traceButtons->addWidget(traceDel);
	traceCommit = new QPushButton(tr("Commit"), traceBox);
	traceButtons->addWidget(traceCommit);
	vboxTrace->addLayout(traceButtons);
	//valueSplitter->addWidget(traceBox);
}

void TokensInput::refresh()
{	
	mTokenView->reset();
	//mTokenView->setCurrentIndex(mTokenModel.index(0,0));
}

void TokensInput::setTrace(Token *token)
{
	mTraceModel.setRowCount(token->trace().size());
	
	int row = 0;
	foreach(Trace t, token->trace()){
		QModelIndex index = mTraceModel.index(row, 0, QModelIndex());
		mTraceModel.setData(index, t.containsToString());
		index = mTraceModel.index(row, 1, QModelIndex());
		mTraceModel.setData(index, t.mount());
		++row;
	}
}

//want to edit a Token
void TokensInput::editToken(const QModelIndex & index)  //the pop up widget can be closed auto? no chance
{
	//Q_ASSERT(index.isValid());
	if (index.isValid()) {
		Token *token = static_cast<Token*>(index.internalPointer());
		mValueWidget->setValue(*token);
		setTrace(token);
	}
}

void TokensInput::moveUp()
{
	QModelIndex index = mTokenView->currentIndex();
	Q_ASSERT(index.isValid());
	int row = index.row();
	if (index.isValid() && row>0){ 
		mTokenModel.moveUp(index);
		QModelIndex preIndex = mTokenModel.index(row-1,0);
		//View is not Updated synchronously. 
		//mTokenView->selectionModel()->setCurrentIndex(preIndex, QItemSelectionModel::Current);
		mTokenView->setCurrentIndex(preIndex);
		//editToken(preIndex);
	}
}

void TokensInput::moveDown()
{
	QModelIndex index = mTokenView->currentIndex();
	Q_ASSERT(index.isValid());
	int row = index.row()+1;
	QModelIndex nextIndex = mTokenModel.index(row,0);
	if (nextIndex.isValid()) {
		mTokenModel.moveUp(nextIndex);//model data is changed, so index and nextIndex are without sense.
		nextIndex = mTokenModel.index(row,0);
		mTokenView->setCurrentIndex(nextIndex);
		//editToken(nextIndex);
	}
}

void TokensInput::addToken()
{
	QModelIndex index = mTokenModel.append(new Token(QVariant(1)));

	mTokenView->setCurrentIndex(index);
}

void TokensInput::deleteToken()
{
	QModelIndex index = mTokenView->currentIndex();
	if (index.isValid()) 
		mTokenModel.deleteAt(index);
}

void TokensInput::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight )
{
	//same: edit one item
	//one line: assign data
	//square: swap
	//Q_ASSERT(topLeft.row()==bottomRight.row());
	//value changed
	//or type changed
	Q_ASSERT(topLeft.isValid() && bottomRight.isValid());
	if (topLeft.row()==bottomRight.row()) 	
		editToken(topLeft);
}

void TokensInput::commitValue()
{
	QModelIndex index = mTokenView->currentIndex();
	Q_ASSERT(index.isValid());
	if (index.isValid()) {
		QModelIndex valueIndex = mTokenModel.index(index.row(),0);
		mTokenModel.setData(valueIndex, mValueWidget->value());
		editToken(index);
	}
}

void TokensInput::addTrace()
{
	int row = mTraceModel.rowCount();
	mTraceModel.insertRow(row);
	QModelIndex index = mTraceModel.index(row,0,QModelIndex());
	mTraceModel.setData(index, "0");
	index = mTraceModel.index(row,1,QModelIndex());
	mTraceModel.setData(index, 0);
}

void TokensInput::deleteTrace()
{
	QModelIndex index = mTraceView->currentIndex();
	if (index.isValid()) {
		mTraceModel.removeRow(index.row());
	}
}

void TokensInput::commitTrace()
{
	QModelIndex index = mTokenView->currentIndex();
	Q_ASSERT(index.isValid());
	if (index.isValid()) {
		QStack<Trace> newTraces;
		Trace one;
		QModelIndex containsIndex, mountIndex;
		for (int i=0; i<mTraceModel.rowCount(); ++i) {
			containsIndex = mTraceModel.index(i,0,QModelIndex());
			mountIndex = mTraceModel.index(i,1,QModelIndex());
			one.setMount(mTraceModel.data(mountIndex).toInt());
			one.stringToContains(mTraceModel.data(containsIndex).toString());
			newTraces.push(one);
		}
		mTokenModel.setTrace(index, newTraces);
		editToken(index);
	}
}